package task

import (
	"errors"
	"fmt"
	"sort"
	"strconv"
	"strings"
	"sync"
	"time"

	"cvevulner/common"
	"cvevulner/models"
	"cvevulner/taskhandler"
	"cvevulner/util"

	"github.com/astaxie/beego"
	"github.com/astaxie/beego/config"
	"github.com/astaxie/beego/logs"
)

var mutex sync.Mutex

// GetGiteeToken Get Code Cloud API TOKEN
func GetGiteeToken() error {
	defer common.Catchs()
	// Query the cve to be processed, 1: add; 2: modify
	BConfig, err := config.NewConfig("ini", "conf/app.conf")
	if err != nil {
		logs.Error("GetGiteeToken, config init error:", err)
		return err
	}
	clientID := BConfig.String("gitee::client_id")
	if clientID == "" {
		logs.Error("GetGiteeToken, config gitee::clientID ,error: invalid value")
		return errors.New("value is nil")
	}
	clientSecret := beego.AppConfig.String("gitee::client_secret")
	if clientSecret == "" {
		logs.Error("GetGiteeToken, config gitee::clientSecret, error: invalid value")
		return errors.New("value is nil")
	}
	Email := BConfig.String("gitee::email")
	if Email == "" {
		logs.Error("GetGiteeToken, config gitee::email, error: value is nil")
		return errors.New("value is nil")
	}
	password := BConfig.String("gitee::password")
	if password == "" {
		logs.Error("GetGiteeToken, config gitee::password, error: value is nil")
		return errors.New("value is nil")
	}
	Scope := BConfig.String("gitee::scope")
	if Scope == "" {
		logs.Error("GetGiteeToken, config gitee::scope, error: value is nil")
		return errors.New("value is nil")
	}
	logs.Info(clientID, clientSecret, password)
	var gt taskhandler.GiteeToken
	gt.GrantType = "password"
	gt.UserName = Email
	gt.Password = password
	gt.ClientID = clientID
	gt.ClientSecret = clientSecret
	gt.Scope = Scope
	taskhandler.GetOautToken(gt)
	return nil
}

// Assemble issue record data
func GenIssueRecordData(icr *models.IssueCreateRecord, issueValue models.VulnCenter, sc models.Score, status int8) {
	icr.CveId = issueValue.CveId
	icr.CveNum = issueValue.CveNum
	icr.Description = issueValue.Description
	icr.CveLevel = issueValue.CveLevel
	icr.Status = status
	icr.CveVersion = issueValue.CveVersion
	icr.RepairTime = issueValue.RepairTime
	icr.PackName = issueValue.PackName
	icr.NVDScore = sc.NVDScore
	icr.NvectorVule = sc.NvectorVule
	icr.CreateTime = common.GetCurTime()
}

func SaveCveTempError(errDesc, cveNum string, cveId int64) {
	if len(errDesc) > 1 {
		models.UpdateTempleteError(errDesc, cveNum, cveId)
	}
}

func ErrorCveStatistics(errDesc string, issueValue models.VulnCenter, status int8) {
	SaveCveTempError(errDesc, issueValue.CveNum, issueValue.CveId)
	if issueValue.OrganizationID == 1 {
		sc, err := models.QueryIssueScore(issueValue.CveId)
		if err != nil || sc.Id == 0 {
			logs.Error("ErrorCveStatistics, Failed to get Score, err: ", err, ", cveId: ", issueValue.CveId)
			return
		}
		icr := models.IssueCreateRecord{ErrorDescription: errDesc}
		GenIssueRecordData(&icr, issueValue, sc, status)
		var it models.IssueTemplate
		it.CveId = issueValue.CveId
		it.CveNum = issueValue.CveNum
		templateErr := models.GetIssueTemplateByColName(&it, "CveId", "CveNum")
		if templateErr == nil {
			if len(it.CreateTime.String()) > 19 {
				icr.CreateTime = it.CreateTime.String()[:19]
			} else {
				icr.CreateTime = it.CreateTime.String()[:19]
			}
		}
		issueRecordId, issReErr := models.CreateIssueRecord(&icr)
		if issReErr == nil && issueRecordId > 0 {
			logs.Info("Issue record data created successfully, id:", issueRecordId)
		} else {
			logs.Error("ErrorCveStatistics, Failed to create issue record data, err: ", issReErr)
		}
	}
}

func CheckCveIssueBranch(packageName, version string) bool {
	submitIssueBranch := beego.AppConfig.String("cve::submit_issue_branch")
	submitIssueBranchSlice := strings.Split(submitIssueBranch, ",")
	branchFlag := false
	if len(version) > 0 {
		versionSlice := strings.Split(version, ",")
		if len(versionSlice) > 0 {
			for _, ver := range versionSlice {
				var oro models.OpenEulerRepoOrigin
				oro.PackageName = packageName
				oro.Version = ver
				_ = models.QueryEulerRepoOrigin(&oro, "PackageName", "Version")
				if oro.Id > 0 {
					if len(submitIssueBranchSlice) > 0 && len(oro.Branchs) > 1 {
						BranchSlice := strings.Split(oro.Branchs, ",")
						if len(BranchSlice) > 0 {
							for _, confBr := range submitIssueBranchSlice {
								for _, br := range BranchSlice {
									if confBr == br {
										branchFlag = true
										goto compareRes
									}
								}
							}
						}
					}
				}
			}
		}
	}
	return branchFlag
compareRes:
	return branchFlag
}

func addUnlimitedIssue(beforeTime string, prcnum, years, toolYears, manYears, flag int, list []string) error {
	for {
		cveData, err := models.QueryIssue(beforeTime, prcnum, list)
		if err == nil && len(cveData) > 0 {
			logs.Info("cveData: ", cveData)
			//ss := rand.Int31n(10)
			//time.Sleep(time.Second * time.Duration(ss))
		} else {
			logs.Info("addUnlimitedIssue, No cve data can be used, current time: ", common.GetCurTime(), ", err: ", err)
			return err
		}
		for index, issueValue := range cveData {
			if models.FilterOldData(issueValue.CveNum) {
				var it models.IssueTemplate
				it.CveId = issueValue.CveId
				it.CveNum = issueValue.CveNum
				templateErr := models.GetIssueTemplateByColName(&it, "CveId", "CveNum")
				if templateErr != nil {
					models.UpdateIssueStatus(issueValue, 12)
					continue
				}
			}
			logs.Info("addUnlimitedIssue, Currently processing：", index, ",cve data, cveNum: ", issueValue.CveNum)
			// add mutex
			lockErr := models.LockUpdateIssueStatus(issueValue.CveId, issueValue.CveNum, 15)
			if !lockErr {
				logs.Info("addUnlimitedIssue, The current cve is processing, continue to process the next data, "+
					"err: ", lockErr, ",data: ", issueValue)
				continue
			}
			owner, accessToken := common.GetOwnerAndToken(issueValue.CveNum, issueValue.OrganizationID)
			// Determine whether the issue has been processed
			goi, oks := models.QueryIssueCveByNum(issueValue.CveNum, issueValue.PackName, issueValue.OrganizationID)
			if oks {
				if strings.ToLower(goi.State) == "closed" || strings.ToLower(goi.State) == "rejected" ||
					goi.State == "已完成" || goi.State == "已拒绝" || goi.IssueState == "已挂起" {
					models.UpdateIssueStatus(issueValue, 2)
					logs.Info("addUnlimitedIssue, The cve data has already been submitted to the issue, "+
						"no need to submit repeatedly, cveData: ", issueValue)
					ErrorCveStatistics("CVE已创建过issue, 且已归档", issueValue, 1)
					continue
				}
			}
			if issueValue.OrganizationID == 1 {
				se := models.SpecError{CveNum: issueValue.CveNum, Owner: owner, PackName: issueValue.PackName, Status: 1}
				seError := models.GetIssueSpecErrByColName(&se, "CveNum", "Owner", "PackName", "Status")
				if seError == nil && se.Id > 0 {
					models.UpdateIssueStatus(issueValue, 5)
					logs.Info("addUnlimitedIssue, The current issue does not need to be processed, "+
						"it has been processed, cveData: ", issueValue)
					ErrorCveStatistics("CVE已经归档无需处理", issueValue, 1)
					continue
				}
				// Determine whether cve has been processed
				issueExist, _ := taskhandler.GetCveSecurityNotice(issueValue.CveNum, issueValue.PackName, true)
				if issueExist {
					models.UpdateIssueStatus(issueValue, 2)
					logs.Info("addUnlimitedIssue, The cve data has been displayed on the official website, "+
						"no need to submit an issue on git, cveData: ", issueValue)
					ErrorCveStatistics("CVE已经在官网展示, 已修复", issueValue, 1)
					continue
				}
				if issueValue.Status == 0 && flag != 2 && len(issueValue.CveVersion) > 0 {
					branchBool := CheckCveIssueBranch(issueValue.PackName, issueValue.CveVersion)
					if !branchBool {
						models.UpdateIssueStatus(issueValue, 8)
						logs.Info("addUnlimitedIssue, "+
							"The current repo branch and version information do not match, "+
							"cveData: ", issueValue)
						ErrorCveStatistics("仓库分支和版本信息不想符合", issueValue, 2)
						continue
					}
				}
			} else if issueValue.OrganizationID == 2 {
				ogc := models.OpenGaussCveList{CveNum: issueValue.CveNum, PackName: issueValue.RepoName, Status: 3}
				ogcErr := models.QueryReleaseCve(&ogc, "CveNum", "PackName", "Status")
				if ogc.Id > 0 {
					models.UpdateIssueStatus(issueValue, 2)
					logs.Info("addUnlimitedIssue, The cve data has been displayed on the official website, "+
						"no need to submit an issue on git, cveData: ", issueValue, ogcErr)
					ErrorCveStatistics("CVE已经在官网展示, 已修复", issueValue, 1)
					continue
				}
			}
			var it models.IssueTemplate
			it.CveId = issueValue.CveId
			it.CveNum = issueValue.CveNum
			templateErr := models.GetIssueTemplateByColName(&it, "CveId", "CveNum")
			if templateErr != nil {
				logs.Warn("addUnlimitedIssue, templateErr:", templateErr, ", CveNum: ", issueValue.CveNum)
			}
			// Import cve as data after 2018
			cveNumList := strings.Split(issueValue.CveNum, "-")
			if cveNumList != nil && len(cveNumList) > 1 {
				cveYears, yearErr := strconv.Atoi(cveNumList[1])
				if yearErr == nil {
					if issueValue.DataSource == 1 || issueValue.DataSource == 5 {
						years = toolYears
					} else if issueValue.DataSource == 3 {
						years = manYears
					}
					if cveYears <= years {
						yearFlag := false
						if it.TemplateId > 0 && len(it.IssueNum) > 0 {
							issueErr, issueBody := taskhandler.GetGiteeIssue(accessToken, owner, issueValue.PackName, it.IssueNum)
							if issueErr == nil && len(issueBody) > 0 {
								yearFlag = true
							}
						}
						if !yearFlag {
							models.UpdateIssueStatus(issueValue, 4)
							logs.Info("addUnlimitedIssue, cve: ", issueValue.CveNum, ",Need to be greater than： ",
								years, ",Otherwise, there is no need to submit an issue on git, cveData: ", issueValue)
							ErrorCveStatistics("CVE年限受限", issueValue, 2)
							continue
						}
					}
				}
			}
			// Process each piece of cve data
			if issueValue.Status == 0 || len(it.IssueNum) < 2 {
				issueValue.Status = 2
				mutex.Lock()
				err := ProcIssue(issueValue, accessToken, owner)
				mutex.Unlock()
				if err != nil {
					logs.Error("addUnlimitedIssue, Failed to create issue, cvenum: ",
						issueValue.CveNum, "err,err: ", err)
					errDesc := fmt.Sprintf("%v", err)
					ErrorCveStatistics(errDesc, issueValue, 2)
					continue
				}
			} else {
				issueValue.Status = 2
				mutex.Lock()
				err := ProcUpdateIssue(issueValue, accessToken, owner)
				mutex.Unlock()
				if err != nil {
					logs.Error("addUnlimitedIssue, Failed to update issue, cvenum: ",
						issueValue.CveNum, "err,err: ", err)
					errDesc := fmt.Sprintf("%v", err)
					ErrorCveStatistics(errDesc, issueValue, 2)
					continue
				}
			}
			// Collect issue record data
			ErrorCveStatistics("success", issueValue, 1)
		}
	}
}

func addLimitedIssue(beforeTime string, prcnum int, years, toolYears, manYears int) error {
	issueWhiteData, issueErr := models.QueryIssueWhitelist(0)
	if issueErr == nil && len(issueWhiteData) > 0 {
		for _, issues := range issueWhiteData {
			if issues.Status == 2 {
				logs.Error("addLimitedIssue, Removed from whitelist, repo: ", issues.PackageName)
				continue
			}
			for {
				cveData, err := models.QueryIssueByPackName(issues.PackageName, beforeTime, prcnum)
				if err == nil && len(cveData) > 0 {
					logs.Info(cveData)
				} else {
					logs.Info("addLimitedIssue, No cve data can be used, "+
						"current time: ", common.GetCurTime(), ", err: ", err)
					break
				}
				for index, issueValue := range cveData {
					logs.Info("addLimitedIssue, Currently processing section: ", index,
						", Cve data, cveNum: ", issueValue.CveNum)
					// add mutex
					lockErr := models.LockUpdateIssueStatus(issueValue.CveId, issueValue.CveNum, 15)
					if !lockErr {
						logs.Error("addLimitedIssue, The current cve is processing, continue to"+
							" process the next data, err: ", lockErr, ",data: ", issueValue)
						continue
					}
					owner, accessToken := common.GetOwnerAndToken(issueValue.CveNum, issueValue.OrganizationID)
					goi, oks := models.QueryIssueCveByNum(issueValue.CveNum, issueValue.PackName, issueValue.OrganizationID)
					if oks {
						if strings.ToLower(goi.State) == "closed" || strings.ToLower(goi.State) == "rejected" ||
							goi.State == "已完成" || goi.State == "已拒绝" || goi.IssueState == "已挂起" {
							models.UpdateIssueStatus(issueValue, 2)
							logs.Info("addLimitedIssue, The cve data has already been submitted to the issue, "+
								"no need to submit repeatedly, cveData: ", issueValue)
							ErrorCveStatistics("CVE已创建过issue, 且已归档", issueValue, 1)
							continue
						}
					}
					// Determine whether the issue has been processed
					if issueValue.OrganizationID == 1 {
						se := models.SpecError{CveNum: issueValue.CveNum, Owner: owner,
							PackName: issueValue.PackName, Status: 1}
						seError := models.GetIssueSpecErrByColName(&se, "CveNum", "Owner", "PackName", "Status")
						if seError == nil && se.Id > 0 {
							models.UpdateIssueStatus(issueValue, 5)
							logs.Info("addLimitedIssue, The current issue does not need to be processed,"+
								" it has been processed, cveData: ", issueValue)
							ErrorCveStatistics("CVE已经归档无需处理", issueValue, 1)
							continue
						}
						// Determine whether cve has been processed
						issueExist, _ := taskhandler.GetCveSecurityNotice(issueValue.CveNum, issueValue.PackName, true)
						if issueExist {
							models.UpdateIssueStatus(issueValue, 2)
							logs.Info("addLimitedIssue, The cve data has been displayed on the official website, "+
								"no need to submit an issue on git, cveData: ", issueValue)
							ErrorCveStatistics("CVE已经在官网展示, 已修复", issueValue, 1)
							continue
						}
						branchBool := CheckCveIssueBranch(issueValue.PackName, issueValue.CveVersion)
						if !branchBool {
							models.UpdateIssueStatus(issueValue, 8)
							logs.Info("addLimitedIssue, The current repo branch and version information do not match, cveData: ", issueValue)
							ErrorCveStatistics("仓库分支和版本信息不想符合", issueValue, 2)
							continue
						}
					} else if issueValue.OrganizationID == 2 {
						ogc := models.OpenGaussCveList{CveNum: issueValue.CveNum, PackName: issueValue.PackName, Status: 3}
						ogcErr := models.QueryReleaseCve(&ogc, "CveNum", "PackName", "Status")
						if ogc.Id > 0 {
							models.UpdateIssueStatus(issueValue, 2)
							logs.Info("addLimitedIssue, The cve data has been displayed on the official website, "+
								"no need to submit an issue on git, cveData: ", issueValue, ogcErr)
							ErrorCveStatistics("CVE已经在官网展示, 已修复", issueValue, 1)
							continue
						}
					}
					// Import cve as data after 2018
					cveNumList := strings.Split(issueValue.CveNum, "-")
					if cveNumList != nil && len(cveNumList) > 1 {
						cveYears, yearErr := strconv.Atoi(cveNumList[1])
						if yearErr == nil {
							if issueValue.DataSource == 1 || issueValue.DataSource == 5 {
								years = toolYears
							} else if issueValue.DataSource == 3 {
								years = manYears
							}
							if cveYears <= years {
								models.UpdateIssueStatus(issueValue, 4)
								logs.Info("addLimitedIssue, cve: ", issueValue.CveNum, ",Need to be greater than: ",
									years, ", Otherwise there is no need to submit an issue on git, cveData: ", issueValue)
								ErrorCveStatistics("CVE年限受限", issueValue, 2)
								continue
							}
						}
					}
					// Process each piece of cve data
					if issueValue.Status == 0 {
						issueValue.Status = 2
						mutex.Lock()
						err := ProcIssue(issueValue, accessToken, owner)
						mutex.Unlock()
						if err != nil {
							logs.Error("addLimitedIssue, Failed to create issue, cvenum: ",
								issueValue.CveNum, ",err: ", err)
							errDesc := fmt.Sprintf("%v", err)
							ErrorCveStatistics(errDesc, issueValue, 2)
							continue
						}
					} else {
						issueValue.Status = 2
						mutex.Lock()
						err := ProcUpdateIssue(issueValue, accessToken, owner)
						mutex.Unlock()
						if err != nil {
							logs.Error("addLimitedIssue, Failed to modify the issue, cvenum: ",
								issueValue.CveNum, "err,err: ", err)
							errDesc := fmt.Sprintf("%v", err)
							ErrorCveStatistics(errDesc, issueValue, 2)
							continue
						}
					}
					// Collect issue record data
					ErrorCveStatistics("success", issueValue, 1)
				}
			}
		}
	} else {
		logs.Error(issueErr)
		return issueErr
	}
	return nil
}

// CreateIssue Create issue
func CreateIssue() error {
	defer common.Catchs()
	logs.Info("The issue task of creating cve begins. . .")
	// Query the cve to be processed, 1: add; 2: modify
	BConfig, err := config.NewConfig("ini", "conf/app.conf")
	if err != nil {
		logs.Error("CreateIssue, config init, error:", err)
		return err
	}
	days, ok := BConfig.Int("crontab::days")
	if ok != nil {
		logs.Error("CreateIssue, config crontab::days, error:", ok)
		return ok
	}
	years, ok := BConfig.Int("cve::cve_number")
	if ok != nil {
		logs.Error("CreateIssue, config cve::years, error:", ok)
		return ok
	}
	manYears, ok := BConfig.Int("cve::cve_number_m")
	if ok != nil {
		logs.Error("CreateIssue, config cve::manYears, error:", ok)
		return ok
	}
	toolYears, ok := BConfig.Int("cve::cve_number_t")
	if ok != nil {
		logs.Error("CreateIssue, config cve::toolYears, error:", ok)
		return ok
	}
	prcnum, ok := BConfig.Int("crontab::prcnum")
	if ok != nil {
		logs.Error("CreateIssue, config crontab::prcnum, error:", ok)
		return ok
	}
	issueWhitelist, ok := BConfig.Int("cve::issue_whitelist")
	if ok != nil {
		logs.Error("CreateIssue, config cve::issue_whitelist, error: ", ok)
		return ok
	}
	// Process lock status data
	models.UpdateLockIssueStatus(15, 0)
	beforeTime := common.GetBeforeTime(days)
	if issueWhitelist == 1 {
		limitErr := addLimitedIssue(beforeTime, prcnum, years, toolYears, manYears)
		logs.Info("CreateIssue, addLimitedIssue, err: ", limitErr)
		logs.Info("The execution of the issue task of creating cve ends. . .")
		return limitErr
	} else {
		unlimitErr := addUnlimitedIssue(beforeTime, prcnum, years, toolYears, manYears, 1, nil)
		logs.Info("CreateIssue, addUnlimitedIssue, err: ", unlimitErr)
		logs.Info("The execution of the issue task of creating cve ends. . .")
		return unlimitErr
	}
}

// ProcUpdateIssue Update issue
func ProcUpdateIssue(issueValue models.VulnCenter, accessToken, owner string) error {
	path := issueValue.PackName
	// Query and modify score
	sr, err := models.QueryIssueScoreRecord(issueValue.CveId, 0)
	if err != nil {
		logs.Error("ProcUpdateIssue, Failed to query score records, CveNum: ",
			issueValue.CveNum, ", err: ", err)
	}
	if sr.NVDScore == 0 {
		var sc models.Score
		score, err := models.QueryIssueScore(issueValue.CveId)
		if err != nil {
			logs.Error("ProcUpdateIssue, Failed to get Score, err: ",
				err, ", CveNum: ", issueValue.CveNum)
			sc.NVDScore = 0
			sc.OpenEulerScore = 0
			sc.NvectorVule = ""
			sc.CveId = issueValue.CveId
			sc.CveNum = issueValue.CveNum
			logs.Error("ProcIssue, Failed to get Score, err: ", err, ", CveNum: ", issueValue.CveNum)
			models.InsertScore(&sc)
			//return errors.New("NVD评分缺失")
		} else {
			sc = score
		}
		sr.NVDScore = sc.NVDScore
		sr.NvectorVule = sc.NvectorVule
		sr.CveId = issueValue.CveId
		if sr.Id > 0 {
			resultNum, upErr := models.UpdateScoreRecord(&sr, "NVDScore", "NvectorVule")
			if upErr != nil {
				logs.Error("UpdateScoreRecord, upErr: ", upErr, resultNum)
			}
		} else {
			sr.Status = 0
			sr.CreateTime = time.Now()
			scoreId, inErr := models.InsertScoreRecord(&sr)
			logs.Error("InsertScoreRecord, upErr: ", inErr, scoreId)
		}
	}
	if issueValue.OrganizationID == 3 {
		// Get branch information
		// Query the repo that needs to submit an issue
		taskhandler.CreateBrandAndTags(accessToken, owner, path, issueValue.OrganizationID)
	}
	// Query issue template
	var it models.IssueTemplate
	it.CveNum = issueValue.CveNum
	it.CveId = issueValue.CveId
	templateErr := models.GetIssueTemplateByColName(&it, "CveNum", "CveId")
	if templateErr == nil && it.TemplateId > 0 {
		it.OwnedVersion = issueValue.CveVersion
		it.Repo = issueValue.PackName
		if len(issueValue.RepoName) > 0 {
			it.OwnedComponent = issueValue.RepoName
		}
		if (it.NVDScore == 0 && sr.NVDScore > 0) || (it.NVDScore > 0 && sr.NVDScore > 0 && it.NVDScore != sr.NVDScore) {
			it.NVDScore = sr.NVDScore
			it.NVDVector = sr.NvectorVule
		}
		it.CveBrief = issueValue.Description
		if it.Assignee == "" && issueValue.OrganizationID == 1 {
			it.Assignee = taskhandler.GetAssignerOfOpeneuler(path)
		}
		_, err := taskhandler.UpdateIssueToGit(accessToken, owner, path, issueValue, it)
		if err != nil && err.Error() != "Recreate issue" {
			logs.Error("ProcUpdateIssue, Failed to update issue template, "+
				"CveNum: ", issueValue.CveNum, "err: ", err)
			// Update issue status
			models.UpdateIssueStatus(issueValue, 3)
			return err
		}
		// Update issue status
		models.UpdateIssueStatus(issueValue, 2)
		// Update score status
		models.UpdateIssueScore(issueValue, 2)
		templetID, err := models.CreateIssueTemplate(&it)
		if err != nil {
			logs.Error("ProcUpdateIssue, Failed to modify issue template, "+
				"CveNum: ", issueValue.CveNum, ",err: ", err)
			//return err
		}
		models.UpdateIssueScoreRe(issueValue, 1)
		logs.Info("ProcUpdateIssue, Successfully updated the issue template, "+
			"CveNum: ", issueValue.CveNum, ", templetID: ", templetID)
		// Judgment of necessary fields
		if (it.NVDScore <= 0 && it.OwnedComponent != "kernel") || len(issueValue.Description) < 2 || len(issueValue.CveNum) < 2 ||
			len(issueValue.PackName) < 2 || len(issueValue.CveVersion) < 1 {
			logs.Error("ProcUpdateIssue, Field is empty: NVDScore: ", it.NVDScore, ",Description: ",
				issueValue.Description, ",CveNum:", issueValue.CveNum, ",PackName: ",
				issueValue.PackName, ",CveVersion: ", issueValue.CveVersion)
			// Update issue status
			models.UpdateIssueStatus(issueValue, 6)
			if it.Status < 3 {
				labelUnFix := beego.AppConfig.String("labelUnFix")
				labelUnFixList := taskhandler.AddLabelValue(accessToken, path, it.IssueNum, owner, labelUnFix, 1)
				_, total := taskhandler.QueryIssueLabels(accessToken, path, it.IssueNum, owner)
				if len(labelUnFixList) > 0 {
					if !eqLabel(labelUnFixList, total) {
						it.IssueLabel = strings.Join(labelUnFixList, ",")
						updateBool := taskhandler.UpdateIssueLabels(accessToken, path, it.IssueNum, owner, it.IssueLabel)
						if !updateBool {
							logs.Error("UpdateIssueLabels, Update failed, IssueNum: ", it.IssueNum)
						}
					}
				}
			}
			return errors.New("CVE的描述和NVD信息缺失")
		}
	}
	return nil
}

func eqLabel(a, b []string) bool {
	sort.Strings(a)
	sort.Strings(b)

	if len(a) != len(b) {
		return false
	}

	for i := 0; i < len(a); i++ {
		if a[i] != b[i] {
			return false
		}
	}
	return true
}

func EulerIssue(issueValue models.VulnCenter, accessToken, owner, path, assignee string, sc models.Score) error {
	sn, err := models.QueryIssueSecurity(issueValue.CveId, issueValue.CveNum)
	if err != nil || sn.CveNum == "" {
		logs.Error("ProcIssue, Failed to obtain security. error: ", err)

		return errors.New("CVE描述缺失")
	}

	assignee = taskhandler.GetAssignerOfOpeneuler(path)

	branchList := make([]string, 0)
	errBrands := errors.New("")
	// Get branch information
	branchList, errBrands = taskhandler.GetBranchesInfo(accessToken, owner, path, issueValue.OrganizationID)
	if branchList == nil || len(branchList) == 0 {
		logs.Error("ProcIssue, Failed to obtain branch information,CveNum: ", issueValue.CveNum,
			", path: ", path, ", err: ", errBrands)
	}
	resp, err := taskhandler.CreateIssueToGit(accessToken, owner, path, assignee, issueValue, sc, branchList)
	if err != nil && err.Error() != "Recreate issue" {
		logs.Error("ProcIssue, Failed to create issue, err: ", err, ",resp: ", resp, ",CveNum: ", issueValue.CveNum)
		// Update issue status
		models.UpdateIssueStatus(issueValue, 3)
		return err
	}
	return nil
}

func GaussIssue(issueValue models.VulnCenter, accessToken, owner, path, assignee string, sc models.Score) error {
	reviewerList, rlerr := models.GetGuassSecurityReviewerList()
	if len(reviewerList) > 0 {
		for _, v := range reviewerList {
			assignee = v.NameSpace
			break
		}
	} else {
		logs.Error("GetGuassSecurityReviewerList, rlerr: ", rlerr)
	}
	guassSecurityAssignee, rerr := models.GetGuassSecurityAssignee(issueValue.RepoName, issueValue.CveVersion)
	if rerr == nil && len(guassSecurityAssignee) > 0 {
		assignee = guassSecurityAssignee
	}
	branchList := make([]string, 0)
	errBrands := errors.New("")
	if len(issueValue.PackName) < 2 {
		gaussIssuePath := beego.AppConfig.String("opengauss::gauss_issue_path")
		path = gaussIssuePath
	} else {
		path = issueValue.PackName
	}
	gaussBranchPath := beego.AppConfig.String("opengauss::gauss_branch_path")
	// Get branch information
	branchList, errBrands = taskhandler.GetBranchesInfo(accessToken, owner, gaussBranchPath, issueValue.OrganizationID)
	if branchList == nil || len(branchList) == 0 {
		logs.Error("ProcIssue, Failed to obtain branch information,CveNum: ", issueValue.CveNum,
			", path: ", path, ", err: ", errBrands)
		gaussVersion := beego.AppConfig.String("opengauss::gauss_version")
		if len(gaussVersion) > 0 {
			gaussVerSlice := strings.Split(gaussVersion, ",")
			if len(gaussVerSlice) > 0 {
				branchList = append(branchList, gaussVerSlice...)
			}
		}
	}
	resp, err := taskhandler.CreateIssueToGit(accessToken, owner, path, assignee, issueValue, sc, branchList)
	if err != nil && err.Error() != "Recreate issue" {
		logs.Error("ProcIssue, Failed to create issue, err: ", err,
			",resp: ", resp, ",cveId: ", issueValue.CveId)
		// Update issue status
		models.UpdateIssueStatus(issueValue, 3)
		return err
	}
	return nil
}

func MindSporeIssue(issueValue models.VulnCenter, accessToken, owner, path, assignee string, sc models.Score) error {
	flag := false
	cveList := strings.Split(issueValue.CveVersion, ",")
	if len(cveList) > 0 {
		for _, vl := range cveList {
			data, _ := models.GetMindSporeYamlAll(&models.MindSporeYaml{PackageName: issueValue.RepoName})
			for _, v := range data {
				version := strings.TrimSpace(string(util.Symbol.ReplaceAll([]byte(v.Version), []byte(""))))
				if v.Repo == issueValue.PackName && taskhandler.JudgeVersion(vl, version, v.Version) {
					assignee = v.Owner
					flag = true
					break
				}
			}
			if flag {
				break
			}
		}
	}
	if !flag || len(assignee) < 1 {
		reviewerList, rlerr := models.GetSporeSecurityReviewerList()
		if len(reviewerList) > 0 {
			for _, v := range reviewerList {
				assignee = v.NameSpace
				break
			}
		} else {
			logs.Error("GetSporeSecurityReviewerList, rlerr: ", rlerr)
		}
	}
	branchList := make([]string, 0)
	// Get branch information
	branchList = taskhandler.CreateBrandAndTags(accessToken, owner, path, issueValue.OrganizationID)
	resp, err := taskhandler.CreateIssueToGit(accessToken, owner, path, assignee, issueValue, sc, branchList)
	if err != nil && err.Error() != "Recreate issue" {
		logs.Error("ProcIssue, Failed to create issue, err: ", err,
			",resp: ", resp, ",cveId: ", issueValue.CveId)
		// Update issue status
		models.UpdateIssueStatus(issueValue, 3)
		return err
	}
	return nil
}

func OpenLooKengIssue(issueValue models.VulnCenter, accessToken, owner, path, assignee string, sc models.Score) error {
	reviewerList, rlerr := models.GetOpenLookengSecurityReviewerList()
	if len(reviewerList) > 0 {
		for _, v := range reviewerList {
			assignee = v.NameSpace
			break
		}
	} else {
		logs.Error("GetSporeSecurityReviewerList, rlerr: ", rlerr)
	}
	branchList := make([]string, 0)
	// Get branch information
	branchList = taskhandler.CreateBrandAndTags(accessToken, owner, path, issueValue.OrganizationID)
	resp, err := taskhandler.CreateIssueToGit(accessToken, owner, path, assignee, issueValue, sc, branchList)
	if err != nil && err.Error() != "Recreate issue" {
		logs.Error("ProcIssue, Failed to create issue, err: ", err,
			",resp: ", resp, ",cveId: ", issueValue.CveId)
		// Update issue status
		models.UpdateIssueStatus(issueValue, 3)
		return err
	}
	return nil
}

// ProcIssue Deal with issue
func ProcIssue(issueValue models.VulnCenter, accessToken, owner string) error {
	owner, accessToken = common.GetOwnerAndToken(issueValue.CveNum, issueValue.OrganizationID, 1)
	if accessToken == beego.AppConfig.String("majun::token") && !common.ValidateMajunPack(issueValue.CveNum, issueValue.RepoName) {
		return nil
	}
	assignee := ""
	path := issueValue.PackName
	// According to the requirements, the missing cve of nvd needs to submit an issue
	var sc models.Score
	score, err := models.QueryIssueScore(issueValue.CveId)
	if err != nil {
		sc.NVDScore = 0
		sc.OpenEulerScore = 0
		sc.NvectorVule = ""
		sc.CveId = issueValue.CveId
		sc.CveNum = issueValue.CveNum
		logs.Error("ProcIssue, Failed to get Score, err: ", err, ", CveNum: ", issueValue.CveNum)
		models.InsertScore(&sc)
		//return errors.New("NVD评分缺失")
	} else {
		sc = score
	}
	legalFlag := false
	if issueValue.DataSource == 4 {
		if len(issueValue.CveNum) < 2 || len(issueValue.PackName) < 2 {
			legalFlag = true
		}
	} else if issueValue.DataSource == 3 {
		if len(issueValue.Description) < 2 || len(issueValue.CveNum) < 2 ||
			len(issueValue.PackName) < 2 || len(issueValue.CveVersion) < 1 {
			legalFlag = true
		}
	} else {
		if len(issueValue.CveNum) < 2 || len(issueValue.PackName) < 2 || len(issueValue.CveVersion) < 1 {
			legalFlag = true
		}
	}
	// Judgment of necessary fields
	if legalFlag {
		logs.Error("ProcIssue, Field is empty: NVDScore: ", sc.NVDScore, ",Description: ",
			issueValue.Description, ",CveNum:", issueValue.CveNum, ",PackName: ",
			issueValue.PackName, ",CveVersion: ", issueValue.CveVersion)
		// Update issue status
		models.UpdateIssueStatus(issueValue, 6)
		return errors.New("CVE的描述或NVD信息缺失")
	}
	switch issueValue.OrganizationID {
	case util.Openeuler:
		if eulerErr := EulerIssue(issueValue, accessToken, owner, path, assignee, sc); eulerErr != nil {
			logs.Error("EulerIssue, eulerErr: ", eulerErr, issueValue.CveNum)
			return eulerErr
		}
	case util.OpenGauss:
		if gaussErr := GaussIssue(issueValue, accessToken, owner, path, assignee, sc); gaussErr != nil {
			logs.Error("GaussIssue, gaussErr: ", gaussErr, issueValue.CveNum)
			return gaussErr
		}
	case util.MindSpore:
		if sporeErr := MindSporeIssue(issueValue, accessToken, owner, path, assignee, sc); sporeErr != nil {
			logs.Error("MindSporeIssue, sporeErr: ", sporeErr, issueValue.CveNum)
			return sporeErr
		}
	case util.OpenLookeng:
		if looKengErr := OpenLooKengIssue(issueValue, accessToken, owner, path, assignee, sc); looKengErr != nil {
			logs.Error("OpenLooKengIssue, looKengErr: ", looKengErr, issueValue.CveNum)
			return looKengErr
		}
	}

	return nil
}

func EmgCreateIssue() error {
	defer common.Catchs()
	// Query the cve to be processed, 1: add; 2: modify
	BConfig, err := config.NewConfig("ini", "conf/app.conf")
	if err != nil {
		logs.Error("CreateIssue, config init, error:", err)
		return err
	}
	years, ok := BConfig.Int("cve::cve_number")
	if ok != nil {
		logs.Error("CreateIssue, config cve::years, error:", ok)
		return ok
	}
	manYears, ok := BConfig.Int("cve::cve_number_m")
	if ok != nil {
		logs.Error("CreateIssue, config cve::manYears, error:", ok)
		return ok
	}
	toolYears, ok := BConfig.Int("cve::cve_number_t")
	if ok != nil {
		logs.Error("CreateIssue, config cve::toolYears, error:", ok)
		return ok
	}
	prcnum, ok := BConfig.Int("crontab::prcnum")
	if ok != nil {
		logs.Error("CreateIssue, config crontab::prcnum, error:", ok)
		return ok
	}
	issueWhitelist, ok := BConfig.Int("cve::issue_whitelist")
	if ok != nil {
		logs.Error("CreateIssue, config cve::issue_whitelist, error: ", ok)
		return ok
	}
	beforeTime := time.Now().Add(-time.Minute * 60).Format("2006-01-02 15:04:05")
	if len(beforeTime) > 19 {
		beforeTime = beforeTime[:19]
	}
	if issueWhitelist == 1 {
		limitErr := addLimitedIssue(beforeTime, prcnum, years, toolYears, manYears)
		logs.Info("CreateIssue, addLimitedIssue, err: ", limitErr)
		logs.Info("The execution of the issue task of creating cve ends. . .")
		return limitErr
	} else {
		unlimitErr := addUnlimitedIssue(beforeTime, prcnum, years, toolYears, manYears, 1, nil)
		logs.Info("CreateIssue, addUnlimitedIssue, err: ", unlimitErr)
		logs.Info("The execution of the issue task of creating cve ends. . .")
		return unlimitErr
	}
}
